<?php

/**
 * Простой менеджер списков. Реализует действия просмотра, создания и
 * редактирования, удаления //и изменения порядка записей таблицы - сделаем как понадобится//.
 *
 */
class Kernel_Manager_List extends Kernel_Manager 
{

    /**
     * "Общее" действие, выполняемое в менеджере.
     *
     */
    const ACTION_COMMON = 1;

    /**
     * Действие, выполняемое над элементом(ами) списка.
     *
     */
    const ACTION_ITEM = 2;

    /**
     * Наименование действия по умолчанию (для всех списков).
     *
     */
    const DEFAULT_ACTION = 'list';

    /**
     * Наименование действия по умолчанию (для данного списка).
     *
     * @var string
     */
    protected $_default = self::DEFAULT_ACTION;
    
    /**
    * List of the default actions which have not to be added by default
    * 
    * @var array
    */
    protected $_exclude_actions = array();

    /**
     * Наименование действия, определенное из пользовательского запроса.
     *
     * @var string
     */
    private $_action;

    /**
     * Массив описаний действий, которые реализует данный менеджер.
     *
     * @var array
     */
    private $_actions = array();

    /**
     * Набор действий менеджера по умолчанию… блина, что-то туго мысль идет.
     * Потом опишу.
     *
     * @var array
     */
    private $_action_types = array(
        'list' => self::ACTION_COMMON,
        'add' => self::ACTION_COMMON,
        'edit' => self::ACTION_ITEM,
        'delete' => self::ACTION_ITEM,
    );
    
    /**
     * Наименование поля - уникального идентификатора записи в таблице.
     *
     * @var string
     */
    protected $_id_field = 'id';
    
    /**
    * Return url to the current manager. If params specified then add the to the 
    * url.
    * 
    * @param array $params
    * @returns string
    */
    static public function managerUrl(array $params = array()) 
    {
        $pairs = array();
        
        foreach ($params as $key => $value) {
            $pairs[] = $key . '=' . rawurlencode($value);
        }
        
        $url = self::_tmp_url(Backend_Filter_Structure::get(array()));
        if (!empty($pairs)) {
            $url .= '&' . implode('&', $pairs);
        }
        return $url;
    }

    
    /**
     * @desc Start filter.
     *
     */
    public function process()
    {
        $this->_setDefaultActions();
        
        $this->_action = Application::getRequest()->get('action', $this->_default);
        
        parent:: process();
        
        Application::getResponse()->assign('manager', array(
            'actions' => $this->_getNavigation(),
        ));
    }

    /**
     * Возвращает описание компонента, который обработает запрошенное
     * действие, полученное из запроса.
     *
     * @return  mixed
     */
    protected function _getFilterToken() 
    {
        return new Kernel_Token($this->_action, $this->_getActionParams($this->_action));
    }

    /**
     * Возвращает параметры, передаваемых в конструктор компонента, реализующего
     * указанное действие.
     *
     * @param   string  $name
     * @return  array
     */
    protected function _getActionParams($name) 
    {
        $id = Application::getRequest()->get($this->_id_field);
        $url = array('redirect_url' => self::_tmp_url(array('id' => '%id')));
        switch ($name){
            case 'list':
                $params = array('actions' => $this->_getItemActions());
                break;
            case 'add':
                $params = $url;
                break;
            case 'edit':
                $params = $url + array('id' => $id);
                break;
            case 'delete':
                $action = array('action' => $this->_default);
                $params = array('back' => self::_tmp_url($action));
                break;
            default:
                $params = array();
                break;
        }
        return $params;
    }

    /**
     * Добавляет действие в менеджер.
     *
     * @param   string  $action
     * @param   integer $type
     */
    protected function _addAction($name, $type, $params = array()) 
    {
        if (array_key_exists($name, $this->_actions)) {
            trigger_error('Action "' . $name . '" already exists', E_USER_ERROR);
        } elseif (!in_array($type, array(self::ACTION_COMMON, self::ACTION_ITEM))) {
            trigger_error('Unsupported action type ' . var_export($type, true), E_USER_ERROR);
        }
        
        if (!in_array($name, $this->_exclude_actions)) {
            $this->_actions[$name] = new Kernel_Manager_List_Action($type, $params);
        }
    }
    
    /**
    * Set default actions.
    * 
    */
    private function _setDefaultActions() 
    {
        foreach (Kernel::getClasses(str_replace('_', DIRECTORY_SEPARATOR, $this->_package()), true) as $name) {
            if (isset($this->_action_types[$name])) {
                $this->_addAction($name, $this->_action_types[$name]);
            }
        }
        
        
    }
    

    /**
     * Возвращает наименования действий указанного типа.
     *
     * @param   integer $type
     * @return  array
     */
    private function _getActions($type) 
    {
        return array_filter($this->_actions, create_function('$action', 'return ' . (int)$type . ' == $action->getType();'));
    }

    /**
     * Возвращает действия для элементов списка.
     *
     * @param   integer $type
     * @return  array
     */
    private function _getItemActions() 
    {
        return array_map(create_function('$action', 'return $action->getParams();'), $this->_getActions(self::ACTION_ITEM));
    }

    /**
     * Возвращает наименования действий указанного типа.
     *
     * @param   integer $type
     * @return  array
     */
    private function _getNavigation() 
    {
        $actions = array();
        foreach (array_keys($this->_getActions(self::ACTION_COMMON)) as $name) {
            $actions[] = array(
                 'name' => $name,
                  'url' => array('action' => $name),
               'active' => $name == $this->_action,
            );
        }
        return $actions;
    }

    /**
     * Формирует URL с указанными параметрами.
     *
     * @param   array   $params
     * @return  string
     */
    static protected function _tmp_url($params = array()) 
    {
        $default = array(); $request = Application::getRequest();
        foreach (Backend_Filter_Structure::params() as $param) {
            $default[$param] = $request->get($param);
        }
        $pairs = array();
        foreach (array_filter(array_merge($default, $params)) as $param => $value) {
            $pairs[] = $param . '=' . rawurlencode($value);
        }
        return '?' . implode('&', $pairs);
    }
    
}
